package com.fita.api.dto.request;

import java.math.BigInteger;
import java.util.Date;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.apache.commons.lang3.StringUtils;
import org.opentravel.ota._2003._05.CompanyNameType;
import org.opentravel.ota._2003._05.CustomerPrimaryAdditionalType;
import org.opentravel.ota._2003._05.CustomerType;
import org.opentravel.ota._2003._05.InventoryStatusType;
import org.opentravel.ota._2003._05.OTAVehAvailRateRQ;
import org.opentravel.ota._2003._05.OTAVehAvailRateRQ.VehAvailRQCore;
import org.opentravel.ota._2003._05.POSType;
import org.opentravel.ota._2003._05.SourceType;
import org.opentravel.ota._2003._05.SourceType.RequestorID;
import org.opentravel.ota._2003._05.TPAExtensionsType;
import org.opentravel.ota._2003._05.VehicleAvailRQAdditionalInfoType;
import org.opentravel.ota._2003._05.VehicleAvailRQCoreType;
import org.opentravel.ota._2003._05.VehicleAvailRQCoreType.VendorPrefs;
import org.opentravel.ota._2003._05.VehicleAvailRQCoreType.VendorPrefs.VendorPref;
import org.opentravel.ota._2003._05.VehicleCoreType;
import org.opentravel.ota._2003._05.VehicleRentalCoreType;
import org.opentravel.ota._2003._05.VehicleTransmissionType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Attr;
import org.w3c.dom.Document;
import org.w3c.dom.Element;

import com.fasterxml.jackson.annotation.JsonFormat;
import com.fita.api.dto.common.CommonVariable;
import com.fita.api.util.XmlUtils;

/**
 * 
 *
 * @author Ark
 *
 */
public class VehicleSearchRequest {
    
    private static final Logger logger = LoggerFactory.getLogger(VehicleSearchRequest.class);
    
    /**
     * 供应商
     */
    private String brand;
    
    /**
     * 套餐cid
     */
    private String setCode;
    
    /**
     * 车辆可用状态
     * 
     *  - Available=可用车辆
     *  - All=所有车辆
     */
    private String status;
    
    /** 取车时间 */
    @JsonFormat(pattern ="yyyy-MM-dd HH:mm:ss")
    private Date pickupDateTime;
    
    /** 还车时间 */
    @JsonFormat(pattern ="yyyy-MM-dd HH:mm:ss")
    private Date returnDateTime;
    
    /** 取车地点 */
    private String pickupLocation;
    
    /** 还车地点 */
    private String returnLocation;
    
    /** 供应商代码 */
    private String vendorPrefCode;
    
    /** 是否空调车 */
    private Boolean airConditionInd;
    
    /** 
     * 自动挡/手动挡
     * 
     *  -Automatic=自动
     *  -Manual=手动
     */
    private String transmissionType;
    
    /** 
     * 燃油类型
     * 
     *  - Unspecified=未指定
     *  - Diesel=柴油
     *  ...
     */
    private String fuelType;
    
    /**
     * 驱动类型
     * 
     *  - Unspecified=未指定
     *  - AWD
     *  - 4WD=四轮驱动
     */
    private String driveType;
    
    /** 车辆类别 */
    private String vehTypeCategory;
    
    /** 
     * 车门数量
     * 
     *  - 2车门=2
     *  - 4车门=4
     *  - Non Specific = omit
     */
    private String vehDoorCount;
    
    /** 车辆型号 */
    private String vehClassSize;
    
    /** 驾龄 */
    private Integer driverTypeAge;
    
    /** 优惠券类型 */
    private String rateQualifier;
    
    /** 优惠券代码 */
    private String promotionCode;
    
    /** 附加设备类型 */
    private String specialEquipType;
    
    /** 附加设备数量 */
    private String specialEquipQuantity;
    
    // ======================== 配置参数 ===========================
    
    private String env;
    
    /**
     * The default constructor
     */
    public VehicleSearchRequest() {
    }
    
    /**
     * @param env
     * @return
     */
    public VehicleSearchRequest initialize(String env) {
        this.env = env;
        return this;
    }
    
    /**
     * @return
     */
    public boolean isValid() {
        return StringUtils.isNotBlank(status) &&
               pickupDateTime != null && 
               returnDateTime != null &&
               StringUtils.isNotBlank(pickupLocation) && 
               StringUtils.isNotBlank(returnLocation) &&
               StringUtils.isNotBlank(brand) &&
               StringUtils.isNotBlank(setCode) &&
               driverTypeAge != null;
    }
    
    /**
     * @return
     * @throws ParserConfigurationException 
     */
    public OTAVehAvailRateRQ generateRq() throws ParserConfigurationException {
        
        OTAVehAvailRateRQ rq = new OTAVehAvailRateRQ();
        
        rq.setPrimaryLangID(CommonVariable.LANGUAGE);
        rq.setTarget(env);
        rq.setVersion(CommonVariable.VERSION);
        rq.setSequenceNmbr(new BigInteger("1"));
        rq.setMaxResponses(new BigInteger("50"));
        
        POSType posType = this.generatePos();
        rq.setPOS(posType);
        
        VehAvailRQCore rqCore = this.generateRQCore();
        rq.setVehAvailRQCore(rqCore);
        
        return rq;
        
    }
    
    /**
     * @return
     */
    private POSType generatePos() {
        
        POSType pos = new POSType();
        
        // source1
        SourceType sourceType1 = new SourceType();
        sourceType1.setISOCountry("CN");
        
        // requestID
        RequestorID requestorID = new RequestorID();
        requestorID.setType(CommonVariable.REQUESTOR_TYPE);
        requestorID.setID(this.setCode);
        logger.info("current set code is [{}]", this.setCode);
        
        // companyName
        CompanyNameType companyName = new CompanyNameType();
        
        if(StringUtils.equalsAnyIgnoreCase(env, "Production")) {
            companyName.setCode("CU");
            companyName.setCompanyShortName("CNTVLSVCXML");
        } else if(StringUtils.equalsAnyIgnoreCase(env, "Testing")) {
            companyName.setCode("EX");
            companyName.setCompanyShortName("EHIXMLTEST");
        }
        
        requestorID.setCompanyName(companyName);
        sourceType1.setRequestorID(requestorID);
        
        // source2
        SourceType sourceType2 = new SourceType();
        
        // requestID
        requestorID = new RequestorID();
        requestorID.setType(CommonVariable.REQUESTOR_TYPE);
        requestorID.setID(this.brand);
        requestorID.setIDContext("IATA");
        
        sourceType2.setRequestorID(requestorID);
        
        pos.getSource().add(sourceType1);
        pos.getSource().add(sourceType2);
        
        return pos;
        
    }
    
    /**
     * @return
     * @throws ParserConfigurationException 
     */
    private VehAvailRQCore generateRQCore() throws ParserConfigurationException {
        
        VehAvailRQCore core = new VehAvailRQCore();
        core.setStatus(InventoryStatusType.fromValue(this.status));
        
        // VehRentalCore
        VehicleRentalCoreType vehicleRentalCoreType = new VehicleRentalCoreType();
        vehicleRentalCoreType.setPickUpDateTime(XmlUtils.convertToXMLGregorianCalendar(this.pickupDateTime));
        vehicleRentalCoreType.setReturnDateTime(XmlUtils.convertToXMLGregorianCalendar(this.returnDateTime));
        
        VehicleRentalCoreType.PickUpLocation pickUpLocation = new VehicleRentalCoreType.PickUpLocation();
        pickUpLocation.setLocationCode(this.pickupLocation);
        vehicleRentalCoreType.getPickUpLocation().add(pickUpLocation);
        
        VehicleRentalCoreType.ReturnLocation returnLocation = new VehicleRentalCoreType.ReturnLocation();
        returnLocation.setLocationCode(this.returnLocation);
        vehicleRentalCoreType.setReturnLocation(returnLocation);
        
        core.setVehRentalCore(vehicleRentalCoreType);
        
        // VendorPrefs
        VendorPrefs vendorPrefs = new VehicleAvailRQCoreType.VendorPrefs();
        
        VendorPref vendorPref = new VendorPref();
        vendorPref.setCode(this.vendorPrefCode);
        vendorPrefs.getVendorPref().add(vendorPref);
        
        core.setVendorPrefs(vendorPrefs);
        
        // VehPrefs
        VehicleAvailRQCoreType.VehPrefs vehPrefs = new VehicleAvailRQCoreType.VehPrefs();
        
        VehicleAvailRQCoreType.VehPrefs.VehPref vehPref = new VehicleAvailRQCoreType.VehPrefs.VehPref();
        if (this.airConditionInd != null) {
            vehPref.setAirConditionInd(this.airConditionInd);
        }
        if (StringUtils.isNotBlank(this.transmissionType)) {
            vehPref.setTransmissionType(VehicleTransmissionType.fromValue(this.transmissionType));
        }
        if (StringUtils.isNotBlank(this.fuelType)) {
            vehPref.setFuelType(this.fuelType);
        }
        if (StringUtils.isNoneBlank(this.driveType)) {
            vehPref.setDriveType(this.driveType);
        }
        
        VehicleCoreType.VehType vehType = new VehicleCoreType.VehType();
        if (StringUtils.isNoneBlank(this.vehTypeCategory)) {
            vehType.setVehicleCategory(this.vehTypeCategory);
        }
        if (StringUtils.isNoneBlank(this.vehDoorCount)) {
            vehType.setDoorCount(this.vehDoorCount);
        }
        vehPref.setVehType(vehType);
        
        VehicleCoreType.VehClass vehClass = new VehicleCoreType.VehClass();
        vehClass.setSize(this.vehClassSize);
        vehPref.setVehClass(vehClass);
        
        vehPrefs.getVehPref().add(vehPref);
        
        core.setVehPrefs(vehPrefs);
        
        // DriverType
        VehicleAvailRQCoreType.DriverType driverType = new VehicleAvailRQCoreType.DriverType();
        driverType.setAge(this.driverTypeAge);
        core.getDriverType().add(driverType);
        
        // RateQualifier
        VehicleAvailRQCoreType.RateQualifier rateQualifier = new VehicleAvailRQCoreType.RateQualifier();
        rateQualifier.setRateQualifier(this.rateQualifier);
        core.getRateQualifier().add(rateQualifier);
        
        TPAExtensionsType extensionsType = this.addExtention();
        core.setTPAExtensions(extensionsType);
        
        return core;
        
    }
    
    /**
     * 
     * @return
     * @throws ParserConfigurationException 
     */
    private TPAExtensionsType addExtention() throws ParserConfigurationException {
        
        TPAExtensionsType extension = new TPAExtensionsType();
        
        DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
        dbFactory.setNamespaceAware(false);
        DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
        Document doc = dBuilder.newDocument();
        
        // root element
        Element rootElement = doc.createElement("TPA_Extension_Flags");
        doc.appendChild(rootElement);
        
        Attr attr = doc.createAttribute("EnhancedTotalPrice");
        attr.setValue("true");
        rootElement.setAttributeNode(attr);
        
        Attr attr2 = doc.createAttribute("IncludedInEstTotalInd");
        attr2.setValue("true");
        rootElement.setAttributeNode(attr2);
        
        String xmlns = "";
        rootElement.removeAttributeNS(xmlns, "xmlns");
        
        String xmlnsns2 = "http://www.opentravel.org/OTA/2003/05";
        rootElement.removeAttributeNS(xmlnsns2, "xmlns:ns2");
        
        extension.getAny().add(rootElement);
        
        return extension;
    }
    
    /**
     * @return
     */
    @SuppressWarnings("unused")
    private VehicleAvailRQAdditionalInfoType generateRQInfo() {
        
        VehicleAvailRQAdditionalInfoType infoType = new VehicleAvailRQAdditionalInfoType();
        
        // Customer
        CustomerPrimaryAdditionalType customer = new CustomerPrimaryAdditionalType();
        
        // Primary
        CustomerPrimaryAdditionalType.Primary primary = new CustomerPrimaryAdditionalType.Primary();
        
        // CustLoyalty
        CustomerType.CustLoyalty custLoyalty = new CustomerType.CustLoyalty();
        custLoyalty.setProgramID("AL");
        custLoyalty.setMembershipID("778125810");
        custLoyalty.setTravelSector("2");
        primary.getCustLoyalty().add(custLoyalty);
        
        customer.setPrimary(primary);
        infoType.setCustomer(customer);
        
        return infoType;
        
    }

    /**
     * @return the brand
     */
    public String getBrand() {
        return brand;
    }

    /**
     * @return the setCode
     */
    public String getSetCode() {
        return setCode;
    }

    /**
     * @return the status
     */
    public String getStatus() {
        return status;
    }

    /**
     * @return the pickupDateTime
     */
    public Date getPickupDateTime() {
        return pickupDateTime;
    }

    /**
     * @return the returnDateTime
     */
    public Date getReturnDateTime() {
        return returnDateTime;
    }

    /**
     * @return the pickupLocation
     */
    public String getPickupLocation() {
        return pickupLocation;
    }

    /**
     * @return the returnLocation
     */
    public String getReturnLocation() {
        return returnLocation;
    }

    /**
     * @return the vendorPrefCode
     */
    public String getVendorPrefCode() {
        return vendorPrefCode;
    }

    /**
     * @return the airConditionInd
     */
    public Boolean getAirConditionInd() {
        return airConditionInd;
    }

    /**
     * @return the transmissionType
     */
    public String getTransmissionType() {
        return transmissionType;
    }

    /**
     * @return the fuelType
     */
    public String getFuelType() {
        return fuelType;
    }

    /**
     * @return the driveType
     */
    public String getDriveType() {
        return driveType;
    }

    /**
     * @return the vehTypeCategory
     */
    public String getVehTypeCategory() {
        return vehTypeCategory;
    }

    /**
     * @return the vehDoorCount
     */
    public String getVehDoorCount() {
        return vehDoorCount;
    }

    /**
     * @return the vehClassSize
     */
    public String getVehClassSize() {
        return vehClassSize;
    }

    /**
     * @return the driverTypeAge
     */
    public Integer getDriverTypeAge() {
        return driverTypeAge;
    }

    /**
     * @return the rateQualifier
     */
    public String getRateQualifier() {
        return rateQualifier;
    }

    /**
     * @return the promotionCode
     */
    public String getPromotionCode() {
        return promotionCode;
    }

    /**
     * @return the specialEquipType
     */
    public String getSpecialEquipType() {
        return specialEquipType;
    }

    /**
     * @return the specialEquipQuantity
     */
    public String getSpecialEquipQuantity() {
        return specialEquipQuantity;
    }

    /**
     * @return the env
     */
    public String getEnv() {
        return env;
    }

    /**
     * @param brand the brand to set
     */
    public void setBrand(String brand) {
        this.brand = brand;
    }

    /**
     * @param setCode the setCode to set
     */
    public void setSetCode(String setCode) {
        this.setCode = setCode;
    }

    /**
     * @param status the status to set
     */
    public void setStatus(String status) {
        this.status = status;
    }

    /**
     * @param pickupDateTime the pickupDateTime to set
     */
    public void setPickupDateTime(Date pickupDateTime) {
        this.pickupDateTime = pickupDateTime;
    }

    /**
     * @param returnDateTime the returnDateTime to set
     */
    public void setReturnDateTime(Date returnDateTime) {
        this.returnDateTime = returnDateTime;
    }

    /**
     * @param pickupLocation the pickupLocation to set
     */
    public void setPickupLocation(String pickupLocation) {
        this.pickupLocation = pickupLocation;
    }

    /**
     * @param returnLocation the returnLocation to set
     */
    public void setReturnLocation(String returnLocation) {
        this.returnLocation = returnLocation;
    }

    /**
     * @param vendorPrefCode the vendorPrefCode to set
     */
    public void setVendorPrefCode(String vendorPrefCode) {
        this.vendorPrefCode = vendorPrefCode;
    }

    /**
     * @param airConditionInd the airConditionInd to set
     */
    public void setAirConditionInd(Boolean airConditionInd) {
        this.airConditionInd = airConditionInd;
    }

    /**
     * @param transmissionType the transmissionType to set
     */
    public void setTransmissionType(String transmissionType) {
        this.transmissionType = transmissionType;
    }

    /**
     * @param fuelType the fuelType to set
     */
    public void setFuelType(String fuelType) {
        this.fuelType = fuelType;
    }

    /**
     * @param driveType the driveType to set
     */
    public void setDriveType(String driveType) {
        this.driveType = driveType;
    }

    /**
     * @param vehTypeCategory the vehTypeCategory to set
     */
    public void setVehTypeCategory(String vehTypeCategory) {
        this.vehTypeCategory = vehTypeCategory;
    }

    /**
     * @param vehDoorCount the vehDoorCount to set
     */
    public void setVehDoorCount(String vehDoorCount) {
        this.vehDoorCount = vehDoorCount;
    }

    /**
     * @param vehClassSize the vehClassSize to set
     */
    public void setVehClassSize(String vehClassSize) {
        this.vehClassSize = vehClassSize;
    }

    /**
     * @param driverTypeAge the driverTypeAge to set
     */
    public void setDriverTypeAge(Integer driverTypeAge) {
        this.driverTypeAge = driverTypeAge;
    }

    /**
     * @param rateQualifier the rateQualifier to set
     */
    public void setRateQualifier(String rateQualifier) {
        this.rateQualifier = rateQualifier;
    }

    /**
     * @param promotionCode the promotionCode to set
     */
    public void setPromotionCode(String promotionCode) {
        this.promotionCode = promotionCode;
    }

    /**
     * @param specialEquipType the specialEquipType to set
     */
    public void setSpecialEquipType(String specialEquipType) {
        this.specialEquipType = specialEquipType;
    }

    /**
     * @param specialEquipQuantity the specialEquipQuantity to set
     */
    public void setSpecialEquipQuantity(String specialEquipQuantity) {
        this.specialEquipQuantity = specialEquipQuantity;
    }

    /**
     * @param env the env to set
     */
    public void setEnv(String env) {
        this.env = env;
    }
}
